package com.tsd.core.utils;

import com.mysql.cj.jdbc.exceptions.MysqlDataTruncation;
import com.tsd.core.vo.HlpException;

import java.io.*;
import java.util.Date;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

/**
 * 异常处理工具类
 *
 * @Author Hillpool
 * @Date 2022-08-28  16:08
 */
public class ExceptionUtil {
    /**
     * 是否网络异常
     *
     * @param e
     * @return
     */
    public static boolean isNetworkError(Exception e) {
        return e instanceof java.net.ConnectException
                || e instanceof java.net.UnknownHostException
                || e instanceof java.net.SocketTimeoutException
                || e instanceof org.apache.http.conn.ConnectTimeoutException;
    }

    /**
     * 获取异常描述，将已知的异常描述用中文表示以便在前端显示便于用户理解
     *
     * @param e1
     * @return
     */
    public static String getExceptionDesc(Exception e1) {
        Throwable e = e1;
        while (e.getCause() != null) {
            e = e.getCause();
        }
        String s;
        if (e instanceof java.net.ConnectException) {
            s = "连接失败，请确认网络已经正常连接";
        } else if (e instanceof java.net.UnknownHostException) {
            s = "无法识别主机，请检查网络是否正常连接";
        } else if (e instanceof java.net.SocketTimeoutException) {
            s = "连接服务器超时";
        } else if (e instanceof NullPointerException) {
            // s = "存在空数据的情况，请与服务商联系";
            s = "存在空数据的情况";
        } else if (e instanceof MysqlDataTruncation) {
            // 匹配单引号的正则表达式
            String msg = e.getMessage();
            if (msg != null) {
                if (msg.contains("Division by 0")) {
                    s = "数据超长了：";
                } else if (msg.contains("Data too long for column")) {
                    String pattStr = "(?<=').*?(?=')";
                    // 创建Pattern并进行匹配
                    Pattern pattern = Pattern.compile(pattStr);
                    Matcher matcher = pattern.matcher(msg);
                    // Data truncation: Data too long for column 'my_doc' at row 1
                    if (matcher.find()) {
                        s = "数据超长了：" + matcher.group();
                    } else {
                        s = "数据超长了：";
                    }
                } else {
                    s = "数据被截断：" + msg;
                }
            } else {
                s = "MysqlDataTruncation";
            }
        } else {
            s = "未明确错误，请与服务商联系";
        }
        return s;
    }

    /**
     * 获取异常的堆栈跟踪信息
     *
     * @param e
     * @return
     */
    public static String getStackTraceFromException(Exception e) {
        try {
            StringWriter sw = new StringWriter();
            PrintWriter pw = new PrintWriter(sw);
            e.printStackTrace(pw);
            return "\r\n" + sw + "\r\n";
        } catch (Exception e2) {
            return e2.getMessage();
        }
    }

    /**
     * 输出出错日志，已日期为目录进行存放
     *
     * @param tag
     * @param e
     */
    public static String writeExceptionLog(String tag, Exception e) {
        String path = ExceptionUtil.class.getResource("/").getPath();
        Date today = new Date();
        String fileName = path + "/../../../../logs/" + HlpUtils.date2String(today, HlpUtils.Format_YyyyMMdd);
        File dir = new File(fileName);
        if (!dir.exists()) {
            dir.mkdirs();
        }
        try {
            fileName = fileName + "/" + tag + "_" + HlpUtils.date2String(today, HlpUtils.Format_YyyyMMddHHmmssSSS) + ".txt";
            writeExceptionInfo2File(fileName, e);
        } catch (Exception e1) {
            e1.printStackTrace();
        }
        return fileName;
    }

    /**
     * 将异常的堆栈跟踪信息输出到指定的文件
     *
     * @param fileName
     * @param e
     * @throws IOException
     */
    public static void writeExceptionInfo2File(String fileName, Exception e) throws IOException {
        ByteArrayOutputStream expMsg = new ByteArrayOutputStream();
        PrintStream out = new PrintStream(expMsg);
        e.printStackTrace(out);
        FileUtil.saveFile(fileName, expMsg.toString().getBytes(), true);
    }

    /**
     * 以HlpException类型抛出异常
     *
     * @param msg
     * @throws Exception
     */
    public static void throwException(String msg) throws HlpException {
        throw new HlpException(msg);
    }

    /**
     * 获取异常的根原因异常
     *
     * @param parent
     * @return
     */
    public static Throwable getRootThrowable(Throwable parent) {
        while (parent.getCause() != null) {
            parent = parent.getCause();
        }
        return parent;
    }
}
